Emberveil source

game/2006Scape Server/src/main/java/org/apollo/cache/decoder/ObjectDefinitionDecoder.java

package org.apollo.cache.decoder;

import java.io.IOException;
import java.io.UncheckedIOException;
import java.nio.ByteBuffer;

import org.apollo.cache.IndexedFileSystem;
import org.apollo.cache.archive.Archive;
import org.apollo.cache.def.ItemDefinition;
import org.apollo.cache.def.ObjectDefinition;
import org.apollo.util.BufferUtil;

/**
 * Decodes object data from the {@code loc.dat} file into {@link ObjectDefinition}s.
 * 
 * @author Major
 * @author Advocatus
 */
public final class ObjectDefinitionDecoder implements Runnable {

	/**
	 * The IndexedFileSystem.
	 */
	private final IndexedFileSystem fs;

	/**
	 * Creates the ObjectDefinitionDecoder.
	 *
	 * @param fs The {@link IndexedFileSystem}.
	 */
	public ObjectDefinitionDecoder(IndexedFileSystem fs) {
		this.fs = fs;
	}

	@Override
	public void run() {
		try {
			Archive config = fs.getArchive(0, 2);
			ByteBuffer data = config.getEntry("loc.dat").getBuffer();
			ByteBuffer idx = config.getEntry("loc.idx").getBuffer();

			int count = idx.getShort() & 0xFFFF, index = 2;
			int[] indices = new int[count];
			for (int i = 0; i < count; i++) {
				indices[i] = index;
				index += idx.getShort() & 0xFFFF;
			}

			ObjectDefinition[] definitions = new ObjectDefinition[count];
			for (int i = 0; i < count; i++) {
				data.position(indices[i]);
				definitions[i] = decode(i, data);
			}

			ObjectDefinition.init(definitions);
		} catch (IOException e) {
			throw new UncheckedIOException("Error decoding ObjectDefinitions.", e);
		}
	}

	/**
	 * Decodes data from the cache into an {@link ObjectDefinition}.
	 *
	 * @param id The id of the object.
	 * @param data The {@link ByteBuffer} containing the data.
	 * @return The object definition.
	 */
	private ObjectDefinition decode(int id, ByteBuffer data) {
		boolean actions = false;
		int[] modelId = null;
		int[] modelType = null;
		ObjectDefinition definition = new ObjectDefinition(id);
		while (true) {
			int opcode = data.get() & 0xFF;

			if (opcode == 0) {
				definition.setInteractive(modelId != null && (modelType == null || modelType[0] == 10));
				if (actions) {
					definition.setInteractive(true);
				}
				return definition;
			} else if (opcode == 1) {
				int amount = data.get() & 0xFF;
				if (amount > 0) {
					if (modelId == null) {
						modelType = new int[amount];
						modelId = new int[amount];
						for (int i = 0; i < amount; i++) {
							modelId[i] = data.getShort() & 0xFFFF;
							modelType[i] = data.get() & 0xFF;
						}
					} else {
						for (int i = 0; i < amount; i++) {
							data.getShort();
							data.get();
						}
					}
				}
			} else if (opcode == 2) {
				definition.setName(BufferUtil.readString(data));
			} else if (opcode == 3) {
				definition.setDescription(BufferUtil.readString(data));
			} else if (opcode == 5) {
				int amount = data.get() & 0xFF;
				if (amount > 0) {
					if (modelId == null) {
						modelType = null;
						modelId = new int[amount];
						for (int i = 0; i < amount; i++) {
							modelId[i] = data.getShort() & 0xFFFF;
						}
					} else {
						for (int i = 0; i < amount; i++) {
							data.getShort();
						}
					}
				}
			} else if (opcode == 14) {
				definition.setWidth(data.get() & 0xFF);
			} else if (opcode == 15) {
				definition.setLength(data.get() & 0xFF);
			} else if (opcode == 17) {
				definition.setSolid(false);
			} else if (opcode == 18) {
				definition.setImpenetrable(false);
			} else if (opcode == 19) {
				definition.setInteractive((data.get() & 0xFF) == 1);
			} else if (opcode == 24) {
				data.getShort();
			} else if (opcode == 28 || opcode == 29) {
				data.get();
			} else if (opcode >= 30 && opcode < 39) {
				actions = true;
				String[] strings = definition.getMenuActions();
				if (strings == null) {
					strings = new String[10];
				}
				String action = BufferUtil.readString(data);
				strings[opcode - 30] = action;
				definition.setMenuActions(strings);
				definition.setInteractive(true);
			} else if (opcode == 39) {
				data.get();
			} else if (opcode == 40) {
				int amount = data.get() & 0xFF;
				for (int i = 0; i < amount; i++) {
					data.getShort();
					data.getShort();
				}
			} else if (opcode == 64) {
				definition.setClipped(false);
			} else if (opcode == 60 || opcode >= 65 && opcode <= 68) {
				data.getShort();
			} else if (opcode == 69) {
				data.get();
			} else if (opcode >= 70 && opcode <= 72) {
				data.getShort();
			} else if (opcode == 73) {
				definition.setObstructive(true);
			} else if (opcode == 75) {
				data.get();
			} else if (opcode == 77) {
				data.getShort();
				data.getShort();
				int count = data.get();
				for (int i = 0; i <= count; i++) {
					data.getShort();
				}
			} else {
				continue;
			}
		}
	}

}